# This class provides all the mechanics for
# importing sites into the new enotify controller
# See script/import/project.rb for usage

require 'pathname'
require 'rexml/document'
require 'parsedate'
require 'csv'


class ThesisImporter

  @errors
  @error_count
  @TEST_MODE = false
  @logger = nil
  @bug_columns = nil
  @site_update_frequency_constantly_id 
  @site_update_frequency_daily_id 
  @site_update_frequency_weekly_id 
  @bug_tool_url_CDETS_id
  @bug_tool_url_QDDTS_id
  
  def initialize
    ##FIXME:: write this to a log file instead of standard out
    @logger = Logger.new(STDOUT)
    @logger.level = Logger::INFO

    @error_count = 0
    @errors = Array.new
    ## load the bug column data 
    @bug_columns = YAML.load(File.read("test/fixtures/bug_columns.yml"))
    
    ## load the ids the for the update frequencies
    @site_update_frequency_constantly_id = SiteUpdateFrequency.find_by_generator_name("constantly").id
    @site_update_frequency_daily_id = SiteUpdateFrequency.find_by_generator_name("daily").id
    @site_update_frequency_weekly_id = SiteUpdateFrequency.find_by_generator_name("weekly").id
    
    # load the bug tool URLs
    @bug_tool_url_CDETS_id = BugToolUrl.find_by_url('http://cdets.cisco.com/apps/goto?identifier=').id
    @bug_tool_url_QDDTS_id = BugToolUrl.find_by_url('http://wwwin-metrics.cisco.com/cgi-bin/ddtsdisp.cgi?id=').id

  end

  
  


  
  # parses and imputs the site_properties.xml file
  # TODO finish mapping to Project Object and save
  def load_project_data(site_home_directory)
    
    p1 = Pathname(site_home_directory)
    p1.children.each do |file|
      if file.directory? then
        
        @logger.info("Importing Site: " + file.to_s)

       
       
        ##   IMPORT SITE PROPERTIES   ##
        current_project = create_project_from_site_xml(file)
        save_object(current_project, current_project.name)



     
        ##    IMPORT SITE QUERIES    ##
        query_properties_file = file.to_s + '/configuration/queries.xml'
        create_bug_lists_from_query_xml(query_properties_file, current_project.id)  

        ##    IMPORT PEOPLE AND SITE RELATIONSHIPS    ##
        loop_over_ownership_files(file.to_s + '/output/owner_lists/', current_project.id)
        
        ## IMPORT PROJECTIONS   ##
        load_projections(file.to_s + '/output/projections/', current_project.id)
        
        ## IMPORT OWNERSHIP CHANGES ##
        import_ownership_changes(file.to_s + '/output/ownership_change/', current_project.id)
        
        ## create the site directories and publish the files
        current_project.publish_site

        @logger.info('Copying History Records to site directory')
        #@logger.info('cp -r ' + file.to_s + '/output/history/* ' + current_project.site_history_directory)
        system('cp -r ' + file.to_s + '/output/history/* ' + current_project.site_history_directory)
        
        @logger.info("Error count for import = " + @error_count.to_s )
        @errors.each do |error|
          @logger.info( error.to_s )
        end
       
        @logger.info("Completed Importing Site: " + file.to_s)
      end # if
    end # each do
  end #load_project_data
    
  def save_object(object, name)
    if (!@TEST_MODE) then
       @logger.info(  "Saving " + name + " to DB." )
       object.save

       if !object.errors.empty?
          @logger.info( "Error Saving " + name + " to DB.")
          object.errors.each{|attr,msg| 
            @logger.info( "#{attr} - #{msg}" )
            @errors.push( "Error Saving " + name + " to DB: " + "#{attr} - #{msg}" )
            @error_count = @error_count + 1
          }
         
          
       end
       
    end # TEST_MODE
  end
    
    
  ## imports a site_properties.xml file into the DB.  
  def create_project_from_site_xml (site_directory)    
 
    @logger.info("Creating Site Properties" + site_directory.to_s)
   
    project = Project.new
           
    @logger.info("New Project Created")
    
           
    doc = REXML::Document.new File.new( site_directory.to_s + '/configuration/site_properties.xml' )
    
    ## short_name
    @logger.info(  File.basename(site_directory.to_s, '.xml') )
    project.short_name = File.basename(site_directory.to_s, '.xml')
       
    
    ## name
    doc.elements.each("site-properties/property[@name='project_name']") { |element| 
      @logger.info( "project_name: " + element.attributes["value"] )
      project.name = element.attributes["value"] 
    }
    
    ## active
    doc.elements.each("site-properties/property[@name='site_active']") { |element| 
      @logger.info(  "site_active: " + element.attributes["value"] )
      project.active = element.attributes["value"]         
    }   
    
 
    
    
        
    ## site_update_frequency
    doc.elements.each("site-properties/property[@name='site_update_frequency']") { |element| 
      @logger.info(  "site_update_frequency: " + element.attributes["value"]  )
      
      if (element.attributes["value"] == 'constantly')
        project.site_update_frequency_id = @site_update_frequency_constantly_id  
      elsif (element.attributes["value"] == 'daily')
        project.site_update_frequency_id = @site_update_frequency_daily_id
      elsif (element.attributes["value"] == 'weekly')
        project.site_update_frequency_id = @site_update_frequency_weekly_id
      else
        @logger.error('Site Update Frequency failed to import for site ' + project.short_name )  
      end
      
             
    }    
    
    
    ## projection_weeks
    doc.elements.each("site-properties/property[@name='number_of_projection_weeks']") { |element| 
      @logger.info( "number_of_projection_weeks: " + element.attributes["value"] )
      project.projection_weeks = element.attributes["value"]         
    }    
    
    

    
    ## bug_tool_url_id
    doc.elements.each("site-properties/property[@name='bug_tool_url']") { |element| 
      @logger.info(  "bug_tool_url: " + element.attributes["value"] )
      project.bug_tool_url_id = site_property_get_but_tool_url(element.attributes["value"] )
    }    
    
    
    ## table_column_order
    ##FIXME: this concept doesn't exist in in the DB. Probably should.
    doc.elements.each("site-properties/property[@name='bug_table_column_order']") { |element| 
      @logger.info(  "old bug_table_column_order: " + element.attributes["value"] )
      
      new_bug_column_order = site_property_get_bug_column_order(element.attributes["value"])
      @logger.info(  "new bug_table_column_order: " + new_bug_column_order )
      project.table_column_order = new_bug_column_order
    }    
    
    ## projection_start_date
    ## CONFIRM: Possible need to parse date?
    ## CONFIRM: yes, parsing is broken. dates show up as 0007 instead of 2007
    doc.elements.each("site-properties/property[@name='projection_start_date']") { |element| 
      old_date = ParseDate.parsedate element.attributes["value"], true   
      formated_date = old_date[1].to_s + '/' + old_date[2].to_s + '/' + old_date[0].to_s
      
      @logger.info(  "projection_start_date " + formated_date )
      project.projection_start_date = formated_date    
    } 


    ## save the project so we can get the project ID in order to use it to map the administrator
    save_object(project, project.name)
      
      
    ## FIXME: map administrator name  & email to the admin table
    doc.elements.each("site-properties/property[@name='administrator_email_address']") { |element| 
      
      @logger.info(  "administrator_email_address: " + element.attributes["value"]  )
      
      #get the email address and strip out the username
      admin_email = element.attributes["value"] 
      
      ## only use the stuff before the @ in the email address
      admin_username = admin_email.split('@')[0]
      
      # lookup the person in the DB 
      admin_person = Person.find_or_create_by_username(admin_username)

      ## FIXME: do I need to save person and project first?

      # put the project index and the person index in the administrators table
      project_admin = Administrator.new
      project_admin.project_id = project.id
      project_admin.person_id = admin_person.id
      
      project_admin.save
      @logger.info(  "administrator_email_address: " + element.attributes["value"]  )
    }    
    

    
     
    return project 
  end # create_project_from_site_xml


  
  ## import the bug lists for a site from query.xml 
  def create_bug_lists_from_query_xml(file, project_id)
    

    
    doc = REXML::Document.new File.new( file )
    
    doc.elements.each("qddts-queries/query-def") { |element| 
      
      list = BugList.new
    
      ## map this list to the current project
      list.project_id = project_id
      
      ## name
      @logger.info( "BugList name: " + element.attributes["name"] )
      list.name = element.attributes["name"] 
      
      ## use projection
      #@logger.info( "use_projections: " + element.attributes["use_projections"] )
      list.use_projections = t_or_f(element.attributes['use_projections'])
      @logger.info( "use_projections: " + list.use_projections.to_s )
      
      ## use_ownership_change
      ##@logger.info( "use_ownership_change " + element.attributes["use_ownership_change"] )
      list.use_ownership_change = t_or_f(element.attributes['use_ownership_change']) 
      @logger.info( "use_ownership_change: " + list.use_ownership_change.to_s )
      
      ## is_verification_list
      ##@logger.info( "is_verification_list " + element.attributes["is_verification_list"] )
      list.is_verification_list = t_or_f(element.attributes['is_verification_list']) 
      @logger.info( "is_verification_list: " + list.is_verification_list.to_s )

      
      ## ownership_model_name
      @logger.info( "ownership_model_name (original): " + element.attributes["ownership_model_name"] )
      ownership_model_id = query_property_get_ownership_model(element.attributes["ownership_model_name"])
      @logger.info( "ownership_model_id (new): " + ownership_model_id.to_s )
      list.ownership_model_id = ownership_model_id

      ## scope_filter
      ## FIXME: scope filter really should not be a string 
      @logger.info( "scope_filter (old): " + element.attributes["scope_filter"] )
      scope_filter_id = query_property_get_scope_filter(element.attributes["scope_filter"])
      @logger.info( "scope_filter (new): " + scope_filter_id.to_s )
      list.scope_filter_id = scope_filter_id


      ## display_name
      ## FIXME: This damn thing doesnt work at all
      puts element.elements['display-name'].text
      @logger.info( "display_name " + nil_fix(element.elements['display-name'].text ))
      list.display_name = nil_fix(element.elements['display-name'].text)

      ## display_name_color
      @logger.info( "display_name_color " + element.elements['display-name'].attributes['color'] )
      list.display_name_color = element.elements['display-name'].attributes['color']
 
      ## description
      @logger.info( "description " + nil_fix(element.elements['description'].text ))
      list.description = nil_fix(element.elements['description'].text)
      
      ## expert_query
      @logger.info( "expert_query " + nil_fix(element.elements['expert-query'].text ))
      list.expert_query = nil_fix(element.elements['expert-query'].text)
      
      ## table_column_order
      ## FIXME: column order to column IDs
      @logger.info( "table_column_order " + element.elements['query_bug_table_column_order'].attributes['value'] )
      list.table_column_order = site_property_get_bug_column_order(element.elements['query_bug_table_column_order'].attributes['value'])
      
      ## override_column_order
      @logger.info( "override_column_order " + element.elements['query_bug_table_column_order'].attributes['override'] )
      list.override_column_order = element.elements['query_bug_table_column_order'].attributes['override']
        
      ## save the bug list          
      save_object(list, list.name)    
      
      
    }
  end  #create_bug_lists_from_query_xml
  
 
   ## starting in the ownership direcotry this iterates 
  ## over all of the ownership files
  def loop_over_ownership_files(ownership_directory, project_id)
    
    
    Pathname(ownership_directory).children.each do |file|

      @logger.info( "parsing: " +file.to_s )

      # put the manager username in the DB
      # and get the manager_id
      @logger.info( "saving manager username: " + File.basename(file.to_s, ".txt"))      
      manager = Person.find_or_create_by_username(File.basename(file.to_s, ".txt"))
      team = Team.new(:project_id => project_id, :person_id => manager.id)
      team.save
      
      CSV::Reader.parse(File.open(file.to_s, 'rb')) do |row|

        @logger.info( "username: " + row[0] )
        person = Person.find_or_create_by_username(row[0])
        @logger.info( "first: " + row[1] )
        person.first_name = row[1]
        @logger.info( "last: " + row[2] )
        person.last_name = row[2]
      
        #same this person 
        @logger.info( "saving person: " + person.username )
        person.save
        
        ## Save the persons relationship to their manager 
        ## and this project
        owner = Owner.new

        owner.team_id = team.id
        owner.person_id = person.id
        
        @logger.info( "saving person as owner: " + person.username )        
        owner.save
        
        
      end

    end
  
  end

    
  def import_ownership_changes(ownership_change_directory, project_id)
    
    #sites\[sitename]\output\ownership_change\bug_list_#.txt
    @logger.info( "###############  IMPORTING OWNERSHIP CHANGES   ###############" )
    
    unless Pathname(ownership_change_directory).exist?  
      ## if there was never an ownership change for this project
      ## the directory wont exist... deal with it by giving 
      ## up and getting a drink
      @logger.info( "There is no ownership chance directory @ " + ownership_change_directory.to_s + " moving on.")
      return
    end
    
    Pathname(ownership_change_directory).children.each do |file|
      ## you have an ownership file for a bug list

      ## get the bug list name out of the file name
      @logger.info( "finding buglist: " + File.basename(file.to_s, ".txt"))
      bug_list_name = File.basename(file.to_s, ".txt")
      bug_list = BugList.find(:first, :conditions => { :name => bug_list_name, :project_id => project_id } )

      #bug_list = BugList.find_by_name(File.basename(file.to_s, ".txt"))

      ## it is possible that someone created a bug list, made
      ## ownership changes, and then deleted the bug list 
      ## this would have left ownership_changes in the system
      ## we have to ignore those changes or we won't be able to
      ## tie them to a bug list
      if bug_list.nil?
        @logger.info( "Skipping import of ownship change for nonexistant bug list: " + File.basename(file.to_s, ".txt"))      
        next
      end
    


      ## loop over each line of the bug list ownerhsip change file
      file = File.new(file, "r")
      while (line = file.gets)
        @logger.info( "parsing: " + line )
        
        ownership_change = BugOwnershipChange.new
     
        ownership_change.bug_list_id = bug_list.id
        
        ownership_array = line.split(':')
        
        ## the format of the ownership change file is: 
        #   bugID:newowner:timestamp:admin_username
        ownership_change.bugid = ownership_array[0]
        ownership_change.new_owner_id = Person.find_or_create_by_username(ownership_array[1]).id
        ## we skip the time stamp in ownership_array[2] because we don't care
        ownership_change.assigner_id = Person.find_or_create_by_username(ownership_array[3]).id
        
        # and we're done with this line. save it!
        save_object(ownership_change, line)
      end
      file.close
      
    end

    
  end
  
        
    
    
  ## go through the projections directory and put all of the projections
  ## into the DB   
  def load_projections(projections_directory, project_id)
    
    @logger.info( "###############   PARSING PROJECTIONS   ###############" )

    Pathname(projections_directory).children.each do |team_directory|
      next if !team_directory.directory?  ## don't parse non directories
      
      ## say which directory we're parsing
      @logger.info('Parsing: ' + File.basename( team_directory.to_s))

      ## get the manager username from the team_folder
      ## FIXME: This is a wild ass guess I have no idea if this syntax is right
      manager_username = File.basename(team_directory.to_s).split("_")[0]

      @logger.info('Manager Username: "' + manager_username + '"')


      ## FIXME: this syntax is a crap shoot too
      manager = Person.find_by_username(manager_username)      

      ## there might be old team directories where the managers are no longer part of the project
      # just punt on these
      next if manager.nil? 
      
      team = Team.find(:first, :conditions => { :person_id => manager.id, :project_id => project_id } )
      

      ## manager is nice, but we actually need to Owner ID name 
      ## for the manager in this project
      ##FIXME: Need to figure out how to do a find lookup on 
      ## this is a wild ass guess!
      ## FIXME: I'm not sure I should be using the owner relationship here...
      #owner = Owner.find( :project_id => project_id, person_id => manager.id)
      ## decided to bail on the owner. served no purpose

      team_directory.children.each do |projection_file|
          
        ## get the bug list name
        bug_list_name = File.basename(projection_file.to_s, ".txt")
        bug_list = BugList.find(:first, :conditions => { :name => bug_list_name, :project_id => project_id } )

        next if bug_list.nil?  ## there might be old bug lists that were deleted
        ## where the projections have been left around
            
            
        CSV::Reader.parse(File.open(projection_file.to_s, 'rb')) do |row|
          projection = Projection.new
          
          ## Add the known info about the bug list and the owner. 
          projection.bug_list_id = bug_list.id
          ## FIXME: I might change this to just be manager ID.
          projection.team_id = team.id
          
          @logger.info( "date: " + Time.at(row[0].to_i).to_s )
          projection.date = Time.at(row[0].to_i)
          @logger.info( "bug_count: " + row[1] )
          projection.bug_count = row[1]
        
          save_object(projection, 'projection')
            
        end ## edn parsing this projection file
        
      end ## end looping through projection files in a team directory.
      
     end ## looping through team projection directories
     
   end ## load_projections
   

     

  
  
  ## takes an objec and replaces it with an empty string if the objec is nil
  def nil_fix(value)
    if (nil == value)
      return ""
    else
      value
    end
  end
  
  
  
  ## returns the applicaion_id given 
  ## the legacy name for that ownership model
  def query_property_get_ownership_model(old_name)
    OwnershipModel.find_by_legacy_name(old_name.to_s).id
 end
  
  ## returns the applicaion_id given 
  ## the legacy name for a scope filter
  def query_property_get_scope_filter(old_name)
    ScopeFilter.find_by_generator_name(old_name.to_s).id
  end

  ## takes a URL and figures out the application_id for 
  ## that URL in the new shcema
  def site_property_get_but_tool_url(legacy_url)
    
    if ( 'http://cdets.cisco.com/apps/goto?identifier='.eql?(legacy_url) )
      # CDETS SI URL found
      return @bug_tool_url_CDETS_id
    elsif   ( 'http://wwwin-metrics.cisco.com/cgi-bin/ddtsdisp.cgi?id='.eql?(legacy_url) )
      # QDDTS URL found
      return @bug_tool_url_QDDTS_id
    else 
      # unrecognized or empty legacy_url. use the default CDETS
      return @bug_tool_url_CDETS_id
    end
    
  end
  
  
  ## this method takes a legacy column order string like
  ##      'Bug ID,OWNER,Due-date,Severity,DE-Priority,Age,State,DE-manager,Found,Headline'
  ## and turns masps each value to it's application_id as 
  ## defined in the bug_columns fixture. 
  ## the result is a string of comma seperated application_ids (integers)
  def site_property_get_bug_column_order(legacy_order)
    
    legacy_order_array = legacy_order.split(',')
    
    ## this will hold the new column order
    new_bug_column_order = Array.new

    unless !legacy_order_array.nil?
        # lookup the id for each column name
        # this will impload if there is a rogue column name in site properties
        # if it does you'll see the error
        # thesis_importer.rb:(LINE_NUMBER): undefined method `[]' for nil:NilClass (NoMethodError)
        # but that should not happen since it's a enotify controlled config file. 
        legacy_order_array.each do |element|
          new_id = @bug_columns[element.to_s]["application_id"]
          new_bug_column_order.push(new_id)
        end
    end
    return new_bug_column_order.join(',')
  end
  
  
  def site_property_load_default_site_frequency ()
      
  end
    
  def t_or_f(value)
    if !value.nil?
        if value.eql?('false')
            return true
        elsif value.eql?('true')
            return true
        end
    end
    return true
  
  end
end